﻿#include <iostream>
#include <sys/epoll.h>
#include <unistd.h>
#include "ArkEpollEvent.h"

namespace kd
{
	/*############################################################################
		fork之前epoll_create的话，所有进程共享一个epoll红黑数。如果我们只需要处理accept事件的话，貌似世界一片美好了。
	但是，epoll并不是只处理accept事件，accept后续的读写事件都需要处理，还有定时或者信号事件。
		当连接到来时，我们需要选择一个进程来accept，这个时候，任何一个accept都是可以的。当连接建立以后，后续的读写事件，
	却与进程有了关联。一个请求与a进程建立连接后，后续的读写也应该由a进程来做。
		fork之前epoll_create，当读写事件发生时，epoll并不知道通知哪个进程，因此，事件有可能错误通知另一个进程，这是不对的。
	我们使用fork之后创建epoll_create()，每个进程的读写事件，只注册在自己进程的epoll中。但这样的话，accept阶段，出现了惊群。
		epoll对惊群的修复，是建立在共享在同一个epoll结构上的。epoll_create在fork之后执行，每个进程有单独的epoll 红黑树，
	等待队列，ready事件列表。因此，惊群再次出现了。
	############################################################################*/
	ArkEpollEvent::ArkEpollEvent(int ev_size, int timeout)
		: epfd(0), ev_size(ev_size), real_ev_size(0), timeout(timeout), ev(), evs(0)
	{
		this->epfd = epoll_create1(0);
		if (this->epfd > 0)
		{
			this->evs = (struct epoll_event*)malloc(sizeof(struct epoll_event) * this->ev_size);
		}
	}

	ArkEpollEvent::~ArkEpollEvent()
	{
		if (this->evs != 0)
		{
			for (int i = 0; i < this->real_ev_size; ++i)
			{
				close(this->evs[i].data.fd);
			}
			free(this->evs);
		}
		close(this->epfd);
	}

	bool ArkEpollEvent::is_ready() const
	{
		return this->epfd > 0 && this->evs != 0;
	}

	bool ArkEpollEvent::add(int fd, int event)
	{
		this->ev.data.fd = fd;
		this->ev.events = event;
		return epoll_ctl(this->epfd, EPOLL_CTL_ADD, fd, &this->ev) == 0;
	}

	bool ArkEpollEvent::del(int fd)
	{
		this->ev.data.fd = fd;
		return epoll_ctl(this->epfd, EPOLL_CTL_DEL, fd, &this->ev) == 0;
	}

	bool ArkEpollEvent::mod(int fd, int event)
	{
		this->ev.data.fd = fd;
		this->ev.events = event;
		return epoll_ctl(this->epfd, EPOLL_CTL_MOD, fd, &this->ev) == 0;
	}

	void ArkEpollEvent::loop(const std::function<void(struct epoll_event*)>& handler)
	{
		this->real_ev_size = epoll_wait(this->epfd, this->evs, this->ev_size, this->timeout);
		int saved_errno = errno;
		if (this->real_ev_size > 0)
		{
			for (int i = 0; i < this->real_ev_size; ++i)
			{
				handler(&this->evs[i]);
			}
		}
		else if (this->real_ev_size == 0)
		{
			// 啥事也没有发生
		}
		else
		{
			// 记录这个罕见的错误
			if (saved_errno != EINTR)
			{
				errno = saved_errno;
			}
		}
	}

	size_t ArkEpollEvent::size() const
	{
		return (size_t)this->ev_size;
	}

	size_t ArkEpollEvent::expires() const
	{
		return (size_t)this->timeout;
	}
}
